﻿using System;
using System.Collections.Generic;
using System.Text;
using PostSharp.Aspects.Dependencies;

namespace Arcana.Contract.Argument.Any.That.Is.Not
{
    /// <summary>
    /// Represents a contract that adheres to <b>At least one item contained in argument is not an instance of a given type</b> semantic.
    /// </summary>
    /// <remarks>
    /// <b>Note: </b>The target argument must be of type <see cref="System.Collection.IEnumerable"/>. Otherwise
    /// <see cref="System.ArgumentException"/> is thrown in validation time. <br />
    /// </remarks>
    [Serializable]
    [ProvideAspectRole(Roles.Contract)]
    [ProvideAspectRole(Roles.Method)]
    [ProvideAspectRole(Roles.Argument)]
    [ProvideAspectRole(Roles.Conditional)]
    [AspectRoleDependency(AspectDependencyAction.Commute, Roles.Conditional)]
    public sealed class InstanceOfAttribute : EnumerableContractBase.ExistentialQuatification
    {
        private Type _type;

        /// <summary>
        /// Initializes a new instance of <b>Argument.Any.That.Is.Not.InstanceOfAttribute</b>.
        /// </summary>
        /// <remarks>
        /// <b>Note: </b>The target argument must be of type <see cref="System.Collection.IEnumerable"/>. Otherwise
        /// <see cref="System.ArgumentException"/> is thrown in validation time. <br />
        /// </remarks>
        /// <param name="argumentName">The argument to which this contract is applied.</param>
        /// <param name="type">The type which at least one item contained in <i>argumentName</i> should be an instance of.</param>
        /// <exception cref="System.ArgumentNullException"><i>argumentName</i> or <i>type</i> are <b>null</b>.</exception>
        public InstanceOfAttribute(string argumentName, Type type)
            : base(argumentName)
        {
            if (type == null) throw new ArgumentNullException();
            _type = type;
        }

        /// <summary>
        /// Performs validation on an item which is stored in an argument of type <see cref="System.Collections.IEnumerable"/>.
        /// </summary>
        /// <remarks>
        /// <b>Note: </b>The target argument must be of type <see cref="System.Collection.IEnumerable"/>. Otherwise
        /// <see cref="System.ArgumentException"/> is thrown in validation time. <br />
        /// </remarks>
        /// <param name="item"></param>
        /// <returns><b>true</b> if <i>item</i> is validated, otherwise <b>false</b>.</returns>
        protected override bool ValidateItem(object item)
        {
            return item == null || !item.GetType().Equals(_type); 
        }
    }
}
